package main

import (
	"fmt"
	"reflect"
)

// pointers 指针
// 指针是一个变量，它存储了另一个变量的内存地址。指针变量声明的一般形式是:
// var var_name *var-type
// 指针变量的类型为 *var-type，var-type 为指针指向的变量的类型。

// 指针的使用
// 指针的使用方式与 C 语言类似，使用 * 操作符可以获取指针指向的变量的值，
// 使用 & 操作符可以获取变量的地址。

//Go语言中的指针操作非常简单，只需要记住两个符号：&（取地址）和*（根据地址取值）。

//当一个指针被定义后没有分配到任何变量时，它的值为 nil

func changX(x *int) {
	*x = 0 // *x 表示 x 指向的变量的值
}

func modifyX(x int) {
	x = 100
}

func main() {
	var p *int
	x := 10
	ptr := new(int) // new() 函数用于分配内存，第一个参数为类型，不支持初始化
	// ------------------- 指针的使用-1  -------------------
	fmt.Println(&x) // &x 表示 x 的内存地址 = 0xc000010088

	y := &x // y 是一个指针，它指向 x 的内存地址 = 0xc000010088
	fmt.Println(y)

	z := *y // *y 表示 y 指向的变量的值. =10
	fmt.Println(z)

	modifyX(x) // 这里的 x 是一个值，不是指针，所以不会改变 x 的值. =10
	fmt.Println(x)

	changX(y)
	fmt.Println(x) // 这里的 x 是一个指针，所以会改变 x 的值. =0

	// ------------------- 指针的使用-2  -------------------
	fmt.Printf("p 的值为 : %s\n", p)
	// 指针的零值
	if p == nil { // 判断指针是否为空
		fmt.Println("空值")
	} else {
		fmt.Println("非空")
	}

	// ------------------- 指针的使用-3  ------------------
	ptr1 := *ptr
	ptr2 := reflect.TypeOf(ptr)
	//fmt.Printf("ptr 的值为 : %d\n", *ptr)  // *ptr 表示 ptr 指向的变量的值. =0
	//fmt.Printf("ptr的类型是: %T\n", ptr)    // ptr的类型是: *int
	//fmt.Printf("ptrd的内存地址是: %p\n", ptr) // ptrd的内存地址是: 0xc000010088
	//fmt.Println(*ptr)
	fmt.Println(ptr)
	fmt.Println(ptr1)
	fmt.Println(ptr2)
}
